/**
 * 
 */
package edu.umd.clip.lm.model.data;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import edu.umd.clip.lm.util.GrowingOutputBuffer;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class OnDiskTrainingDataWriter implements TrainingDataWriter {
	private FileChannel output;
	private GrowingOutputBuffer buffer;
	private int bufferSize;
	public static final int DEFAULT_BUFFER_SIZE = 1024*1024;

	public OnDiskTrainingDataWriter(FileChannel output, int bufferSize) {
		this.output = output;
		this.bufferSize = bufferSize;
	}

	public OnDiskTrainingDataWriter(FileChannel output) {
		this(output, DEFAULT_BUFFER_SIZE);
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.model.training.TrainingDataWriter#write(edu.umd.clip.lm.model.training.WritableTrainingData, edu.umd.clip.lm.model.training.TrainingDataBlock)
	 */
	@Override
	public void write(WritableTrainingData data, TrainingDataBlock block) throws IOException {
		block.write(buffer);
		//System.err.printf("Block written: GrowingBuffer.size = %d\n", buffer.size());
		if (buffer.size() >= bufferSize) {
			buffer.flip();
			buffer.drainTo(output);
			buffer = new GrowingOutputBuffer(bufferSize);
		}
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.model.training.TrainingDataWriter#createData()
	 */
	@Override
	public WritableTrainingData createData() {
		return new WritableTrainingData(this);
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.model.training.TrainingDataWriter#finish(edu.umd.clip.lm.model.training.WritableTrainingData)
	 */
	@Override
	public void finish(WritableTrainingData data) {
		try {
			buffer.flip();
			buffer.drainTo(output);
			buffer = null; // no more writing
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.model.training.TrainingDataWriter#start(edu.umd.clip.lm.model.training.WritableTrainingData)
	 */
	@Override
	public void start(WritableTrainingData data) {
		buffer = new GrowingOutputBuffer(bufferSize);
		ByteBuffer buf = ByteBuffer.allocate(AbstractTrainingData.HEADER_SIZE);
		data.writeHeader(buf);
		buf.flip();
		buffer.put(buf);
	}

}
